using System;
using System.Collections;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;

namespace Pegasus.UnitTests.Runtime.Serialization.Formatters.Xml.XmlFormatter2Tests
{
	/// <summary>
	/// This is a test class for Pegasus.Runtime.Serialization.Formatters.Xml.XmlFormatter2
	/// and will check the complex object graphs and the serialization events.
	///</summary>
	[TestClass]
	public class XmlFormatter2ComplexTests
	{
		// Local Instance Values
		private TestContext m_testContextInstance;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:XmlFormatter2ComplexTests"/> class.
		/// </summary>
		public XmlFormatter2ComplexTests()
		{
		}

		/// <summary>
		/// Gets or sets the test context which provides information about and 
		/// functionality for the current test run.
		/// </summary>
		/// <value>The test context.</value>
		public TestContext TestContext
		{
			get
			{
				return m_testContextInstance;
			}
			set
			{
				m_testContextInstance = value;
			}
		}

		/// <summary>
		/// Serializes the object references and return the object via a proxy.
		/// </summary>
		[TestMethod]
		public void SerializeObjectReferencesTest1()
		{
			Singleton startObj = Singleton.GetInstance();
			startObj.Name = XmlFormatter2Helper.StringTestValue;

			Singleton finishedObj = (Singleton) XmlFormatter2Helper.SerializeDeserialize( startObj );

			// Check test results
			Assert.AreEqual( finishedObj.Name, XmlFormatter2Helper.StringTestValue, "The name value is not correct" );
		}

		/// <summary>
		/// Serializes an array of the object references and return the object via a proxy.
		/// </summary>
		[TestMethod]
		public void SerializeObjectReferencesTest2()
		{
			Singleton[] startArray = new Singleton[ XmlFormatter2Helper.TestLoops ];
			for( int x = 0; x < XmlFormatter2Helper.TestLoops; x++ )
			{
				startArray[ x ] = Singleton.GetInstance();
			}

			Singleton[] finishedArray = (Singleton[]) XmlFormatter2Helper.SerializeDeserialize( startArray );

			// Check test results
			Assert.AreEqual( finishedArray.Length, XmlFormatter2Helper.TestLoops, "Array length does not match" );

			for( int x = 0; x < XmlFormatter2Helper.TestLoops; x++ )
			{
				Assert.IsNotNull( finishedArray[ x ], "Array element is null" );
				Assert.AreSame( finishedArray[ x ], Singleton.GetInstance(), "Array element is not the singleton" );
			}
		}


		/// <summary>
		/// Serializes the multiple referenced object.
		/// </summary>
		[TestMethod]
		public void SerializeMultipleReferencedObject()
		{
			Hashtable table = new Hashtable();

			SerializationChild refObj = new SerializationChild();
			refObj.Name = XmlFormatter2Helper.StringTestValue;
			refObj.Description = XmlFormatter2Helper.StringTestValue;
			refObj.Count = XmlFormatter2Helper.IntTestValue;
			refObj.NonserializeCount = XmlFormatter2Helper.IntTestValue;

			for( int x = 0; x < XmlFormatter2Helper.TestLoops; x++ )
			{
				table.Add( x, refObj );
			}

			Hashtable finishedTable = (Hashtable) XmlFormatter2Helper.SerializeDeserialize( table );

			// Check test results
			int count = finishedTable.Count;
			Assert.AreEqual( count, XmlFormatter2Helper.TestLoops, "Table count is wrong" );

			SerializationChild firstObj = (SerializationChild) finishedTable[ 0 ];
			int hashCode = firstObj.GetHashCode();
			SerializationChild lastObj = (SerializationChild) finishedTable[ count - 1 ];

			for( int x = 0; x < XmlFormatter2Helper.TestLoops; x++ )
			{
				SerializationChild otherObj = (SerializationChild) finishedTable[ x ];

				Assert.IsNotNull( otherObj, "Deserialize return null object" );
				Assert.AreEqual( otherObj.Name, XmlFormatter2Helper.StringTestValue, "Name value is not right" );
				Assert.AreEqual( otherObj.Description, XmlFormatter2Helper.StringTestValue, "Description value is not right" );
				Assert.IsNull( otherObj.OtherObject, "OtherObject value is not right" );
				Assert.AreEqual( otherObj.Count, XmlFormatter2Helper.IntTestValue, "Count value is not right" );
				Assert.AreNotEqual( otherObj.NonserializeCount, XmlFormatter2Helper.IntTestValue, "NonCount value is not right" );

				// All hash codes should be the same (because it's the same object)
				Assert.AreEqual( otherObj.GetHashCode(), hashCode, "Hash code is wrong" );
			}

			// Change the name of one and the name on all reference should change
			firstObj.Name = "New Name";
			Assert.AreEqual( lastObj.Name, "New Name", "The object values did not change as expected." );
		}

		/// <summary>
		/// Serializes the events test.
		/// </summary>
		[TestMethod]
		public void SerializeEventsTest()
		{
			OnSerializationEventsObject startObj = new OnSerializationEventsObject();
			startObj.Name = XmlFormatter2Helper.StringTestValue;

			// Send the object through the serializtion and deserializtion process
			OnSerializationEventsObject finishedObj = (OnSerializationEventsObject) XmlFormatter2Helper.SerializeDeserialize( startObj );

			// Check test results
			Assert.IsTrue( startObj.Serializing, "The OnSerializing event was not called in serializliation phase" );
			Assert.IsTrue( startObj.Serialized, "The OnSerialized event was not called in serializliation phase" );
			Assert.IsFalse( startObj.Deserializing, "The OnDeserializing event was called in serializliation phase" );
			Assert.IsFalse( startObj.Deserialized, "The OnDeserialized event was called in serializliation phase." );
			Assert.IsFalse( startObj.Deserialized, "The IDeserializationCallback event was called in serializliation phase." );

			Assert.IsNotNull( finishedObj, "Deserialize return null object" );
			Assert.AreEqual( finishedObj.Name, XmlFormatter2Helper.StringTestValue, "Name value is not right" );
			Assert.IsFalse( finishedObj.Serializing, "The OnSerializing event was called in deserializliation phase" );
			Assert.IsFalse( finishedObj.Serialized, "The OnSerialized event was called in deserializliation phase" );
			Assert.IsTrue( finishedObj.Deserializing, "The OnDeserializing event was not called in deserializliation phase" );
			Assert.IsTrue( finishedObj.Deserialized, "The OnDeserialized event was not called in deserializliation phase." );
			Assert.IsTrue( finishedObj.Deserialized, "The IDeserializationCallback event was not called in deserializliation phase." );
		}

        public void SerializeTypeTest()
        {
            int aInt = 3;
            string aString = "a string";
            Dictionary<int, Hashtable> aDict = new Dictionary<int, Hashtable>();

            Type intType = (Type) XmlFormatter2Helper.SerializeDeserialize( aInt.GetType() );
            Type stringType = (Type) XmlFormatter2Helper.SerializeDeserialize( aString.GetType() );
            Type dictType = (Type) XmlFormatter2Helper.SerializeDeserialize( aDict.GetType() );

            Assert.AreEqual( intType, aInt.GetType() );
            Assert.AreEqual( intType, aString.GetType() );
            Assert.AreEqual( intType, aDict.GetType() );
        }
    }
}
